home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v10n12.arc
/
DPMI.C
< prev
next >
Wrap
Text File
|
1991-05-30
|
8KB
|
255 lines
/*
DPMI.C -- DPMI functions, plus some undocumented Windows functions that
provide the same functionality, plus several layers of "sugar coating"
on top of these low-level services, to make them palatable
Copyright (c) 1991 Ziff Communications Co.
PC Magazine * Andrew Schulman
*/
#include <windows.h>
#include <dos.h>
#include "dpmi.h"
#define MAKEP(seg, ofs) ((void far *) MAKELONG((ofs), (seg)))
BOOL dpmi_present(void)
{
_asm mov ax, 1686h
_asm int 2fh
_asm not ax
}
void dpmi_version(unsigned *pmaj, unsigned *pmin,
unsigned *pflags, unsigned *pproc)
{
unsigned char maj, min, proc;
unsigned flags;
_asm {
mov ax, 0400h
int 31h
mov maj, ah
mov min, al
mov flags, bx
mov proc, cl
}
*pmaj = maj;
*pmin = min;
*pflags = flags;
*pproc = proc;
}
/* Performs a real-mode interrupt from protected mode */
BOOL dpmi_rmode_intr(unsigned intno, unsigned flags,
unsigned copywords, RMODE_CALL far *rmode_call)
{
if (flags) intno |= 0x100;
_asm {
push di
mov ax, 0300h // simulate real-mode interrupt
mov bx, word ptr intno // interrupt number, flags
mov cx, word ptr copywords // words to copy from pmode to rmode stack
les di, dword ptr rmode_call // ES:DI = addr of rmode call struct
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm xor ax, ax // return FALSE
done:
_asm pop di
}
/* Allocates a single protected-mode LDT selector */
unsigned dpmi_sel(void)
{
_asm {
xor ax, ax // Allocate LDT Descriptors
mov cx, 1 // allocate just one
int 31h // call DPMI
jc error
jmp short done // AX holds new LDT selector
}
error:
_asm xor ax, ax // failed
done:;
}
BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
{
_asm {
push di
mov ax, 000ch // Set Descriptor
mov bx, word ptr pmodesel // protected mode selector
les di, dword ptr d // descriptor
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm xor ax, ax // return FALSE
done:
_asm pop di
}
BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
{
_asm {
push di
mov ax, 000bh // Get Descriptor
mov bx, word ptr pmodesel // protected mode selector
les di, dword ptr d // descriptor
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm xor ax, ax // return FALSE
done:
_asm pop di
}
BOOL dpmi_sel_free(unsigned pmodesel)
{
_asm {
mov ax, 0001h // Free LDT Descriptor
mov bx, word ptr pmodesel // selector to free
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm xor ax, ax // return FALSE
done:;
}
/* Layer on top of DPMI and Windows services ******************************/
unsigned DosAllocRealSeg(DWORD bytes, unsigned *ppara, unsigned *psel)
{
DWORD dw = GlobalDosAlloc(bytes);
if (dw == NULL)
return 8; /* insufficient memory */
*ppara = HIWORD(dw);
*psel = LOWORD(dw);
return 0;
}
unsigned DosFreeRealSeg(unsigned sel)
{
return (GlobalDosFree(sel) != NULL);
}
/*
Use DPMI services to map a real-mode paragraph into protected-mode
address space. First we get a selector using the DPMI "Allocate
LDT Descriptors" call (INT 31h Function 0000h), via our dpmi_sel()
function. We then get the descriptor for any old data segment in
our program so that it can be used as a template of sorts for the
new descriptor. This is done with the DPMI "Get Descriptor" call
(INT 31h Function 000Bh), via our dpmi_get_descriptor() function.
We then alter the descriptor to reflect the "rmpara" and "size"
requested, and finally associate the descriptor with our LDT
selector, using the DPMI "Set Descriptor" call (INT 31h Function
000Ch). All the user needs, of course, is the selector itself.
*/
unsigned DosMapRealSeg(unsigned rmpara, DWORD size, unsigned far *psel)
{
DESCRIPTOR d;
unsigned long addr;
unsigned sel = dpmi_sel();
if (! sel)
return 8; /* insufficient memory */
/* make sure psel is valid */
if (! verw(FP_SEG(psel)))
return 490; /* invalid selector error */
/* get descriptor for any data segment */
dpmi_get_descriptor(FP_SEG(psel), &d);
d.limit = (unsigned) size - 1;
addr = ((unsigned long) rmpara) << 4L;
d.addr_lo = (unsigned) addr;
d.addr_hi = (unsigned char) (addr >> 16);
d.reserved = d.addr_xhi = 0;
dpmi_set_descriptor(sel, &d);
*psel = sel;
return 0; /* success */
}
unsigned DosFreeSeg(unsigned sel)
{
return ! dpmi_sel_free(sel);
}
/*
Use undocumented Windows function to retrieve the real-mode
equivalent to a protected mode pointer. Of course, we could also
have used dpmi_get_descriptor() here, but GetSelectorBase()
is slightly more convenient. If the base of the selector is
above the one-megabyte watershed, then there is no real-mode
equivalent, so we return NULL.
*/
void far *DosProtToReal(void far *prot)
{
unsigned long base = GetSelectorBase(FP_SEG(prot));
if (base > 0xFFFFFL)
return NULL; /* not accessible in real mode */
else
return MAKEP(base >> 4, (base & 0x0F) + FP_OFF(prot));
}
unsigned __0000H = 0; /* undocumented Windows selector */
unsigned mapped = 0; /* keep track of number of mapped selectors */
unsigned get_mapped(void) { return mapped; }
/*
Map a real-mode pointer into our protected mode address space.
If the real-mode pointer is in the first 64k of memory, use the
undocumented Windows selector __0000H. Otherwise, use DPMI
services via our DosMapRealSeg() function, which provides a more
convenient layer on top of DPMI. This map_real() function in
turn provides a more convenient layer on top of DosMapRealSeg().
Note that DosMapRealSeg() takes a paragraph address, whereas
map_real takes a full segment:offset real-mode pointer.
*/
void far *map_real(void far *rptr, unsigned long size)
{
unsigned seg, ofs, sel;
if (! __0000H) /* one time init: get undocumented Windows selector */
__0000H = LOWORD(GetProcAddress(GetModuleHandle("KERNEL"),"__0000H"));
seg = FP_SEG(rptr);
ofs = FP_OFF(rptr);
if ((seg < 0x1000) && ((ofs + size) < 0xFFFF))
return MAKEP(__0000H, (seg << 4) + ofs);
if (DosMapRealSeg(seg, size + ofs, &sel) != 0)
return 0;
mapped++;
return MAKEP(sel, ofs);
}
void free_mapped_seg(void far *fp)
{
unsigned sel = FP_SEG(fp);
if (sel == __0000H)
return;
if (DosFreeSeg(sel) == 0)
mapped--;
}
/* Use Intel VERW instruction to validate pointers */
unsigned verw(unsigned sel)
{
_asm mov ax, 1
_asm verw sel
_asm je short ok
_asm xor ax, ax
ok:;
}